home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 3 / CD ACTUAL 3.iso / linux / sonido / mod-0.000 / mod-0 / mod / play.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-29  |  10.3 KB  |  421 lines

  1. /*
  2.  *  play.c - Plays module
  3.  *
  4.  *  (C) 1994 Mikael Nordqvist (d91mn@efd.lth.se, mech@df.lth.se)
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <fcntl.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/soundcard.h>
  15. #include <sys/ultrasound.h>
  16. #include <limits.h>
  17. #include <sys/time.h>
  18.  
  19. #include "mod.h"
  20. #include "message.h"
  21.  
  22. /* Sample #0 is used as a "silent sample" that will cause the active voice
  23.  * to be silenced.
  24.  */
  25.  
  26. SEQ_DECLAREBUF();
  27. extern int seqfd, gus_dev;
  28. extern struct mod_info M;
  29. extern struct options opt;
  30.  
  31. /* Variables used to play module */
  32.  
  33. struct voice V[MAX_VOICES];
  34. struct effects efx;
  35. struct event *cur_event;
  36.  
  37. int songpos, linepos, tick, speed, tempo;
  38. double mod_time, tick_time;
  39. char is_first_ult_effect;
  40.  
  41. char song_end, restart_song, advance_songpos;
  42.  
  43. /* Used to make sure we notify main of speed/tempp-changes */
  44. static int last_speed, last_tempo;
  45.  
  46. /* Tables */
  47. extern int periodtable[NR_OCTAVES*12];
  48.  
  49. void play_tick(void)
  50. {
  51.     int i;
  52.  
  53.     if(_seqbufptr)
  54.     error("Buffer not flushed on entry to play_tick()\n");
  55.  
  56.     tick++;
  57.     if(tick >= speed) { /* Next line/position ... */
  58.     tick=0;
  59.  
  60.     if(efx.pattern_delay)   /* Update patterndelay if needed */
  61.         --efx.pattern_delay;
  62.     
  63.     /* Check line jumps (EFX_LOOP) on tick #0 in each line */
  64.         
  65.     if(efx.PBreakFlag) {
  66.         linepos=efx.PBreakPos;
  67.         efx.PBreakPos=0;
  68.         efx.PBreakFlag=0;
  69.         advance_songpos=0;
  70.     }
  71.     
  72.     /* Check patternjumps (EFX_BREAK|JMP) on tick #0 in each line. */
  73.     
  74.     /* NOTE: A line with EFX_LOOP and then EFX_BREAK on a voice with
  75.      * higher number will change pattern and start on line 0 regardless
  76.      * of the argument to EFX_BREAK. This seems like a bug, but
  77.      * as this is the behaviour of ProTracker, we will emulate it.
  78.      */
  79.         
  80.     if(efx.PosJumpFlag) {
  81.         linepos=efx.PBreakPos;  /* Set line to continue at */
  82.         advance_songpos=1;
  83.     }
  84.     else {
  85.         if(!efx.pattern_delay) {
  86.         if(++linepos == 64) { /* Just advance normally */
  87.             linepos=0;
  88.             advance_songpos=1;
  89.         }
  90.         }
  91.     }
  92.  
  93.     if(advance_songpos) {
  94.         songpos++;
  95.         if(M.format == MODFORMAT_MOD || M.format == MODFORMAT_MTM)
  96.         songpos=(songpos&0x7f); /* PT/MTM allows 0x80 songpos's */
  97.         if(M.format == MODFORMAT_ULT)
  98.         songpos=(songpos&0xff); /* ULT allows 0x100 songpos's */
  99.         if(M.format == MODFORMAT_S3M) {
  100.         while(songpos < M.songlength) {
  101.             if(M.patterntable[songpos] == S3M_ORDER_SKIP) {
  102.             songpos++;
  103.             continue;
  104.             }
  105.             if(M.patterntable[songpos] == S3M_ORDER_SONGEND)
  106.             songpos=M.songlength;
  107.             break;
  108.         }
  109.         }
  110.  
  111.         /* End song if it's done or an invalid pattern # is found */
  112.         if(songpos >= M.songlength ||
  113.            M.patterntable[songpos] > M.nr_patterns) {
  114.         restart_song=1;
  115.         if(opt.loop_module || (!opt.break_loops && M.restartpos))
  116.             songpos=M.restartpos;
  117.         else
  118.             song_end=1;
  119.         }
  120.         efx.PBreakPos=0;
  121.         efx.PosJumpFlag=0;
  122.         restart_song=0;     /* Either set above or in EFX_JUMP */
  123.     }
  124.     }
  125.     
  126.     if(song_end) {
  127.     for(i=0; i < M.nr_voices; ++i)
  128.         MY_SEQ_STOP_NOTE(gus_dev, i, V[i].note, 0);
  129.     
  130.     SEQ_WAIT_TIME((int)mod_time+10); /* Wait 100 extra milli-seconds */
  131.     SEQ_WAIT_TIME((int)mod_time+11); /* Dummy to make sure we don't exit
  132.                       * until above events has taken effect
  133.                       */
  134.     SEQ_ECHO_BACK(MESSAGE_DONE);
  135.     return; /* No printing or processing when song is done */
  136.     }
  137.     
  138.     SEQ_WAIT_TIME((int)(mod_time+0.5));
  139.     i=_seqbufptr;
  140.     
  141.     if(!tick && !efx.pattern_delay) {
  142.     if(advance_songpos)
  143.         advance_songpos=0;
  144.     
  145.     /* ALWAYS send speed _before_ line (catchup-code depends on this! */
  146.     if(speed != last_speed || tempo != last_tempo) {
  147.         send_speed();
  148.         last_speed=speed;
  149.         last_tempo=tempo;
  150.     }
  151.     send_line();
  152.     }
  153.  
  154.     process_line(efx.pattern_delay ? 1 : 0);
  155.     
  156.     mod_time+=tick_time;
  157.     if(_seqbufptr == i) /* Remove WAIT-event if possible */
  158.     _seqbufptr=0;
  159. }
  160.  
  161.  
  162. /* When continue_effects is nonzero we just continue uppdating effects that
  163.  * are updated when tick is nonzero (this is for EFX_PATTERNDELAY).
  164.  */
  165.  
  166. void process_line(int continue_effects)
  167. {
  168.     int v;
  169.     struct event tmp_event, *orig_event;
  170.     int this_songpos=songpos; /* In case songpos gets changes in EFX_? */
  171.  
  172.     for(v=0; v < M.nr_voices; ++v) {
  173.     efx.set_volume=0;
  174.     efx.set_finepitch=0;
  175.     efx.set_balance=0;
  176.     efx.dont_trigger_note=0;
  177.     efx.retrig_note=0;
  178.     efx.kill_voice=0;
  179.  
  180.     cur_event=GET_EVENT_PTR(v, M.patterntable[this_songpos], linepos);
  181.     
  182.     if(!tick && !continue_effects) { /* Tick #0 */
  183.         
  184.         /* Sample change on the voice? */
  185.         if(cur_event->sample) {
  186.         if(cur_event->sample <= M.nr_samples &&
  187.            M.sample[cur_event->sample].valid) {
  188.             if(cur_event->sample != V[v].sample) {
  189.             /* See TECH-file for a comment on changing samples
  190.              */
  191.             SEQ_SET_PATCH (gus_dev, v, cur_event->sample);
  192.             V[v].sample=cur_event->sample;
  193.             }
  194.             
  195.             /* Try to reduce number of calls to do_set_finepitch() */
  196.             if(V[v].finetune != M.sample[cur_event->sample].finetune
  197.                || V[v].pitchbend)
  198.             efx.set_finepitch=1;
  199.             
  200.             V[v].finetune=M.sample[cur_event->sample].finetune;
  201.             V[v].sampleoffset=0;
  202.         }
  203.         else {
  204.             /* Change to nonspecified sample -> silence the voice */
  205.             efx.kill_voice=1;
  206.         }
  207.         }
  208.         /* Reset volume to default instrument-volume if we have
  209.          * a (valid) sample specified. Also make sure it affects
  210.          * a sample that is already playing.
  211.          */
  212.         if(cur_event->sample && M.sample[cur_event->sample].valid) {
  213.         V[v].volume=V[v].real_volume=M.sample[V[v].sample].volume;
  214.         efx.set_volume=1;
  215.         }
  216.         
  217.         /* Second effect is used for "volume"-field in S3M's */
  218.         if(M.format == MODFORMAT_S3M && cur_event->effect2 == EFX_VOLUME) {
  219.         V[v].volume=V[v].real_volume=cur_event->arg2;
  220.         efx.set_volume=1;
  221.         }
  222.         
  223.         is_first_ult_effect=1;
  224.         check_tick0_efx(v); /* Check effects */
  225.  
  226.         /* Check second effect if its a .ULT-file.
  227.          * This is 'hack' but it does the job w/o requiring modifications
  228.          * to effects.c.
  229.          */
  230.         if(M.format == MODFORMAT_ULT) {
  231.         is_first_ult_effect=0;
  232.         tmp_event=*cur_event;
  233.         orig_event=cur_event;
  234.         cur_event=&tmp_event;
  235.         cur_event->effect=cur_event->effect2;
  236.         cur_event->arg=cur_event->arg2;
  237.         
  238.         check_tick0_efx(v);
  239.         cur_event=orig_event;
  240.         }
  241.  
  242.         /* Silence voice if needed */
  243.         if(efx.kill_voice) {
  244.         V[v].sample=0;
  245.         V[v].volume=V[v].real_volume=0;
  246.         MY_SEQ_START_NOTE(gus_dev, v, 255, 0);
  247.         }
  248.  
  249.         /* Set balance if needed */
  250.         if(efx.set_balance)
  251.         SEQ_PANNING(gus_dev, v, ((int)M.panning[v])*17-128);
  252.  
  253.         /* If we have a note and no EFX_PORTANOTE(&VS) or EFX_NOTEDELAY,
  254.          * we trigger it (unless it's a NOTE_OFF ofcourse)
  255.          */
  256.         if(cur_event->note && cur_event->note != NOTE_OFF &&
  257.            !efx.dont_trigger_note) {
  258.         if(V[v].sample) {
  259.             MY_SEQ_START_NOTE(gus_dev, v, cur_event->note,
  260.                       convert_volume(V[v].real_volume));
  261.             if(V[v].sampleoffset)
  262.             GUS_VOICE_POS(gus_dev, v, V[v].sampleoffset);
  263.             if(efx.set_finepitch)
  264.             do_set_finepitch(v);
  265.         }
  266.         }
  267.         else { /* No note to play, change volume/finepitch if needed
  268.             * (and there is a sample specified for the voice).
  269.             */
  270.         if(cur_event->note == NOTE_OFF)
  271.             MY_SEQ_STOP_NOTE(gus_dev, v, 0, 0);
  272.  
  273.         if(V[v].sample) {
  274.             if(efx.set_volume)
  275.             MY_SEQ_START_NOTE(gus_dev, v, 255,
  276.                        convert_volume(V[v].real_volume));
  277.             if(efx.set_finepitch)
  278.             do_set_finepitch(v);
  279.         }
  280.         }
  281.     }
  282.     else {  /* NOT tick #0 */
  283.         is_first_ult_effect=1;
  284.         check_efx(v); /* Update effects */
  285.         
  286.         /* Update second effect if its a .ULT-file.
  287.          */
  288.         if(M.format == MODFORMAT_ULT) {
  289.         is_first_ult_effect=0;
  290.         tmp_event=*cur_event;
  291.         orig_event=cur_event;
  292.         cur_event=&tmp_event;
  293.         cur_event->effect=cur_event->effect2;
  294.         cur_event->arg=cur_event->arg2;
  295.         
  296.         check_efx(v);
  297.         cur_event=orig_event;
  298.         }
  299.         
  300.         if(V[v].sample) {
  301.         if((efx.retrig_note && cur_event->note != NOTE_OFF) ||
  302.            efx.set_volume)
  303.             MY_SEQ_START_NOTE(gus_dev, v,
  304.                    (efx.retrig_note ? cur_event->note : 255),
  305.                    convert_volume(V[v].real_volume));
  306.         
  307.         if((efx.retrig_note && cur_event->note != NOTE_OFF) &&
  308.            V[v].sampleoffset)
  309.             GUS_VOICE_POS(gus_dev, v, V[v].sampleoffset);
  310.         
  311.         /* Here we always set finepitch if we have efx.retrig_note
  312.          * as the efx.set_finepitch that is set at tick #0 is already
  313.          * cleared, and there could be a finetunedifference.
  314.          */
  315.         if(efx.retrig_note || efx.set_finepitch)
  316.             do_set_finepitch(v);
  317.         }
  318.     }
  319.     }
  320. }
  321.  
  322.  
  323. void total_reset(int spd, int tmpo, int pos)
  324. {
  325.     init_sequencer_voices(); /* Must be done first */
  326.     init_voices();
  327.  
  328.     last_speed=last_tempo=-1;
  329.     speed=spd;
  330.     tempo=tmpo;
  331.     tick_time=250.0/tempo;
  332.  
  333.     SEQ_START_TIMER();
  334.     mod_time=0;
  335.     SEQ_WAIT_TIME(0);
  336.     SEQ_DUMPBUF();
  337.     tick=speed;
  338.  
  339.     set_modulepos(pos);
  340. }
  341.  
  342.  
  343. void init_sequencer_voices(void)
  344. {
  345.     int i;
  346.     
  347.     ioctl(seqfd, SNDCTL_SEQ_RESET, 0);     /* Kill events */
  348.     i=750;
  349.     ioctl(seqfd, SNDCTL_SEQ_TRESHOLD, &i); /* Set threshold */
  350.     _seqbufptr=0;
  351.     GUS_NUMVOICES(gus_dev, M.nr_voices);
  352.     SEQ_VOLUME_MODE(gus_dev, VOL_METHOD_LINEAR);
  353.  
  354.     for(i=0; i < M.nr_voices; ++i) {
  355.     SEQ_PANNING(gus_dev, i, ((int)M.panning[i])*17-128);
  356.     SEQ_BENDER_RANGE(gus_dev, i, 8191);
  357.     SEQ_PITCHBEND(gus_dev, i, 0);
  358.     }
  359. }
  360.  
  361.  
  362. void init_voices(void)
  363. {
  364.     int i;
  365.  
  366.     for(i=0; i < M.nr_voices; ++i) {
  367.     /* Clear voice-info */
  368.     bzero((void*)&V[i], sizeof(struct voice)); 
  369.     
  370.     /* Waveforms are retriggered sines by default */
  371.     V[i].vibrato_waveform=WAVEFORM_SINE;
  372.     V[i].vibrato_retrig=1;
  373.     V[i].tremolo_waveform=WAVEFORM_SINE;
  374.     V[i].tremolo_retrig=1;
  375.     V[i].loopstartpos=-1;
  376.  
  377.     /* Set note and period to valid values so pitchbender won't screw up */
  378.     V[i].note=BASE_NOTE+4*12;
  379.     V[i].period=V[i].real_period=periodtable[V[i].note-BASE_NOTE];
  380.     }
  381. }
  382.  
  383.  
  384. void set_modulepos(int pos)
  385. {
  386.     efx.pattern_delay=0;
  387.     
  388.     efx.PosJumpFlag=0;
  389.     efx.PBreakFlag=0;
  390.     efx.PBreakPos=0;
  391.     
  392.     songpos=pos-1;
  393.     linepos=63;
  394.     song_end=0;
  395.     restart_song=0;
  396. }
  397.  
  398.  
  399. /* Converts 'v' to a volumelevel suitable for the sounddriver */
  400.  
  401. int convert_volume(int v)
  402. {
  403.     return MIN((v*128)/M.volrange, 127);
  404. }
  405.  
  406.  
  407. /* Sets the pitch for a voice. Should actually be in effects.c, but I wanted
  408.  * to keep it clean from sequencer-commands.
  409.  */
  410.  
  411. void do_set_finepitch(int v)
  412. {
  413.     set_pitch(v);
  414.     
  415.     SEQ_PITCHBEND(gus_dev, v, V[v].pitchbend+(V[v].finetune*100)/8);
  416. #if 0
  417.     if(opt.active_voices&(1<<v) && opt.verbose >=5)
  418.     printf("'%d+%d",V[v].pitchbend, V[v].finetune);
  419. #endif
  420. }
  421.